// OCC也就是Occupancy  Mode占用模式，当检测到运动时，占用模式将打开灯，并在设定的时间没有运动后关闭灯
#include "occ_mode.h"
#include "pir_sensor_detect.h"
#include "relay_ctrl.h"
#include "key.h"
#include "pir_sensor_detect.h"
#include "timeout_conf.h"
#include "systime.h"
#include "brightness_detect.h"

#define PIR_FILTER_TIME 2500    // 单位ms,负载关闭后PIR的关闭滤波时间
#define KEY_PIR_OFF_TIME 30000L // 单位ms,按键关闭负载后PIR关闭的时间

#define PIR_TEMP_ON_TIME 5000   // 临时开灯时间，单位ms
#define PIR_TEMP_ON_THRESHOLD 10 // 临时开灯期间检测到人的次数阈值

typedef enum
{
    OCCUPANCY_STATE_INIT,
    OCCUPANCY_STATE_DET,
    OCCUPANCY_STATE_TEMP_ON,
    OCCUPANCY_STATE_ON,
    OCCUPANCY_STATE_OFF,
    OCCUPANCY_STATE_OFF_PROCESS,
    OCCUPANCY_STATE_UNOCCUPIED_CONFIRM,
    OCCUPANCY_STATE_OFF_FILTER,
} occupancy_state_e;

static struct
{
    timestamp_t unoccupied_timeout; // 无人状态的超时时间
    timestamp_t pir_filter_timeout; // PIR关闭后的滤波时间
    timestamp_t temp_on_timeout;    // 临时开灯超时
    occupancy_state_e state;
    relay_state_e relay_state;
    uint16_t unoccupied_timeout_conf; // 单位s，旋钮设置的无人关断时间
    uint16_t pir_disable_time;        // 单位ms，PIR禁用的持续时间
    uint8_t temp_on_count;            // 临时开灯检测计数

} occupancy_mode_ctx;

void occ_mode_init(void)
{
    occupancy_mode_ctx.state = OCCUPANCY_STATE_INIT;
    occupancy_mode_ctx.relay_state = RELAY_OFF;
    occupancy_mode_ctx.unoccupied_timeout_conf = 0;
    occupancy_mode_ctx.pir_disable_time = 0;
}

void occ_mode_state_deinit(void)
{
    occupancy_mode_ctx.state = OCCUPANCY_STATE_INIT;
}

void occ_mode_task(void)
{
    switch (occupancy_mode_ctx.state)
    {
    case OCCUPANCY_STATE_INIT:
        pir_sensor_set_status(PIR_SENSOR_ENABLED);
        occupancy_mode_ctx.state = OCCUPANCY_STATE_DET;
        break;
    case OCCUPANCY_STATE_DET:
        occupancy_mode_ctx.relay_state = get_relay_sw();
        if (RELAY_ON == occupancy_mode_ctx.relay_state)
        {
            occupancy_mode_ctx.state = OCCUPANCY_STATE_TEMP_ON;
        }
        else if (RELAY_OFF == occupancy_mode_ctx.relay_state)
        {
            occupancy_mode_ctx.state = OCCUPANCY_STATE_OFF;
        }
        break;
    case OCCUPANCY_STATE_TEMP_ON: // 临时开灯状态
        if (pir_sensor_is_occupied())
        {
            occupancy_mode_ctx.temp_on_count++;
            if (occupancy_mode_ctx.temp_on_count >= PIR_TEMP_ON_THRESHOLD)
            {
                // 如果检测到人的次数足够多，进入正常开灯状态
                occupancy_mode_ctx.unoccupied_timeout_conf = timeout_conf_get_sec(); // 设置无人超时时间
                relative_time_add_sec(&occupancy_mode_ctx.unoccupied_timeout, occupancy_mode_ctx.unoccupied_timeout_conf);
                occupancy_mode_ctx.state = OCCUPANCY_STATE_ON;
            }
            else
            {
                // 继续延长临时开灯时间
                relative_time_add_ms(&occupancy_mode_ctx.temp_on_timeout, PIR_TEMP_ON_TIME);
            }
        }
        else if (is_relative_time_timeout(&occupancy_mode_ctx.temp_on_timeout))
        {
            // 临时开灯时间结束，关闭灯
            set_relay_sw(RELAY_OFF);
            occupancy_mode_ctx.state = OCCUPANCY_STATE_OFF;
        }
        break;
    case OCCUPANCY_STATE_ON:
        if (is_key_click())
        {                                                           // 有按键按下
            occupancy_mode_ctx.pir_disable_time = KEY_PIR_OFF_TIME; // PIR关闭30s
            occupancy_mode_ctx.state = OCCUPANCY_STATE_OFF_PROCESS;
        }
        else if (!pir_sensor_is_occupied())
        {                                                                        // 无感应
            occupancy_mode_ctx.unoccupied_timeout_conf = timeout_conf_get_sec(); // 单位s
            relative_time_add_sec(&occupancy_mode_ctx.unoccupied_timeout, occupancy_mode_ctx.unoccupied_timeout_conf);
            occupancy_mode_ctx.state = OCCUPANCY_STATE_UNOCCUPIED_CONFIRM;
        }
        break;
    case OCCUPANCY_STATE_UNOCCUPIED_CONFIRM:
        if (pir_sensor_is_occupied())
        {
            occupancy_mode_ctx.state = OCCUPANCY_STATE_ON;
        }
        else if (is_relative_time_timeout(&occupancy_mode_ctx.unoccupied_timeout))
        {
            occupancy_mode_ctx.pir_disable_time = PIR_FILTER_TIME; // PIR关闭滤波2.5s
            occupancy_mode_ctx.state = OCCUPANCY_STATE_OFF_PROCESS;
        }
        else if (is_key_click())
        {
            occupancy_mode_ctx.pir_disable_time = KEY_PIR_OFF_TIME; // PIR关闭30s
            occupancy_mode_ctx.state = OCCUPANCY_STATE_OFF_PROCESS;
        }
        break;
    case OCCUPANCY_STATE_OFF_PROCESS:               // 关闭负载处理
        pir_sensor_set_status(PIR_SENSOR_DISABLED); // 关闭PIR
        set_relay_sw(RELAY_OFF);                    // 关闭负载
        relative_time_add_ms(&occupancy_mode_ctx.pir_filter_timeout, occupancy_mode_ctx.pir_disable_time);
        occupancy_mode_ctx.state = OCCUPANCY_STATE_OFF_FILTER;
        break;
    case OCCUPANCY_STATE_OFF_FILTER:
        if (is_key_click())
        {
            set_relay_sw(RELAY_ON);                    // 打开负载
            pir_sensor_set_status(PIR_SENSOR_ENABLED); // 打开PIR
            occupancy_mode_ctx.state = OCCUPANCY_STATE_ON;
        }
        else if (is_relative_time_timeout(&occupancy_mode_ctx.pir_filter_timeout))
        {                                              // 滤波完成
            pir_sensor_set_status(PIR_SENSOR_ENABLED); // 打开PIR
            occupancy_mode_ctx.state = OCCUPANCY_STATE_DET;
        }
        break;
    case OCCUPANCY_STATE_OFF:
        if (is_key_click())
        {
            set_relay_sw(RELAY_ON);
            occupancy_mode_ctx.state = OCCUPANCY_STATE_DET;
        }
        else if (is_brightness_satisfy()) 
        { // 光照满足ON的条件
            if (pir_sensor_is_occupied())
            {
                set_relay_sw(RELAY_ON);
                occupancy_mode_ctx.temp_on_count = 0;
                relative_time_add_ms(&occupancy_mode_ctx.temp_on_timeout, PIR_TEMP_ON_TIME);
                occupancy_mode_ctx.state = OCCUPANCY_STATE_TEMP_ON;
            }
        }
        break;

    default:
        break;
    }
}
